#pragma once

#include<iostream>
#include<string>
#include<jsoncpp/json/json.h>
#include"Logger.hpp"
//定制协议

static const std::string linesep = "\r\n";

class Request
{
public:
    Request():_x(0),_y(0),_oper(0)
    {}
    //序列化:将字符串转换为json 风格的长字符换，并返回
    bool Seriailze(std::string* out)
    {   
        Json::Value root;
        //以kv风格
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;

        //返回json串, 使用styledwrite 中的write
        Json::StyledWriter writer;
        *out = writer.write(root);
        if(out->empty()) return false;
        return true;
    }
    //反序列化：将json串，转换为结构字段
    bool Deserialze(const std::string& in)//输入型参数
    {
        Json::Value root;
        Json::Reader reader;
        bool ret = reader.parse(in , root);
        if(ret==false) return false;

        _x = root["x"].asInt();
        _y = root["y"].asInt();
        _oper = root["oper"].asInt();
        return true;
    }

    int X()
    {
        return _x;
    }

    int Y()
    {
        return _y;
    }

    char Oper()
    {
        return _oper;
    }
    ~Request(){}
// private:
    int _x;
    int _y;
    char _oper;
};

class Response
{
public:
    Response():_result(0),_code(0)
    {}
    //序列化，将应答数据变成JSON串；输出型参数
    bool Seriailze(std::string* out)
    {
        Json::Value root;
        Json::StyledWriter writer;
        root["result"]= _result;
        root["code"] = _code;

        *out = writer.write(root);
        if(out->empty()) return false;
        return true;
    }
    //将获取到的应答报文从字符串转换成json串，并放到结构字段中
    bool Deserialze(const std::string& in)//输入型参数
    {   
        Json::Value root;
        Json::Reader reader;
        bool ret = reader.parse(in, root);
        if(!ret) return false;

        //从root 中将数据放入结构字段中
        _result = root["result"].asInt();
        _code = root["code"].asInt();
        return true;
    }

    void SetResult(int r)
    {
        _result = r;
    }

    void SetCode(int c)
    {   
        _code = c;
    }

    //方便debug
    void Print()
    {
        std::cout << _result << "[" << _code << "]" << std::endl;
    }
    ~Response()
    {}
private:
    int _result;
    int _code;
};
 
//整合协议 ： 收到请求，返回处理之后的应答
class Protocol
{
public:
    //打包与解包，确保读取到的报文是完整的
    //将请求进行打包，在字符串前面添加有效载荷的长度，以\r\n 作分隔符
    static std::string Package(const std::string& jsonstr)
    {
        //首先需要判断jsonstr 是否为空
        if(jsonstr.empty()) return std::string();

        std::string lenstr = std::to_string(jsonstr.size());

        //添加有效载荷长度
        return lenstr + linesep + jsonstr + linesep;
    }
    static bool DigitCheck(const std::string& str)
    {
        for(auto e: str)
        {
            if(!(e>='0' && e <='9')) return false;
        }
        return true;
    }
    //将报文解包，判断报文是否完整；完整就返回报文
    static int Unpack(std::string& origin_str , std::string* out)//第一个为输入输出型参数，第二个为输出型参数
    {
        //获取有效载荷长度
        if(out == nullptr) return 0;

        auto pos = origin_str.find(linesep);
        // std::cout << "pos: " << pos;
        if(pos==std::string::npos) return 0;//表示一定没有读取到完整的报文，继续读取


        //获取有效载荷长度，并判断协议是否合法
        std::string len_str = origin_str.substr(0,pos);
        if(DigitCheck(len_str)==false) return -1;//表示协议错误
        int len = std::stoi(len_str);
        // LOG(LogLevel::DEBUG) << "获取到了描述有效载荷长度的字段：" << len;

        //判断报文是否完整
        int target_len = len_str.size() + linesep.size()*2 + len;

        // LOG(LogLevel::DEBUG) << "有效载荷长度：" << len << ", 报文总长度：" << target_len;

        if(origin_str.size() < target_len) return 0;//报文不完整，继续读取报文

        //走到了这个地方表示至少有一个完整的报文
        *out = origin_str.substr(pos+linesep.size() , len);
        //对origin_str 中已经获取的报文做删除处理
        origin_str.erase(0,target_len);

        // LOG(LogLevel::DEBUG) << "获取到的报文: " << *out << ",大小；" <<out->size(); 
        
        return out->size();//返回获取报文中有效载荷的长度
    }
};